package com.app.sgd.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ResourceBundle;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionServlet;

import com.app.sgd.plugin.JNDIConnector;
import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;


public class DownloadUtil {
	private static Logger logger = Logger.getLogger(DownloadUtil.class);
	
	DataSource ds = null;
	JNDIConnector cn = new JNDIConnector();
	
	private class ReplaceInfo {
		int posStart;
		int posNext;
		byte[] replaceValue;
	}

	private ActionServlet servlet;
 
	private HttpServletRequest request;

	private HttpServletResponse response;

	private Collection replacePairs = null;

	private byte keys[][] = null;

	private String values[] = null;

	public static final byte PREFIX[] = { '{', '{' };

	public static final byte SUFIX[] = { '}', '}' };

	public DownloadUtil(ActionServlet servlet, HttpServletRequest request, HttpServletResponse response) {
		this.servlet = servlet;
		this.request = request;
		this.response = response;
	}

	public void addReplacePair(String key, String value) {
		if (replacePairs == null)
			replacePairs = new ArrayList();
		char[] keyArr = key.toCharArray();
		byte[] keyBytes = new byte[keyArr.length];

		int pos = 0;

		for (int i = 0; i < keyArr.length; i++)
			keyBytes[pos++] = (byte) keyArr[i];

		replacePairs.add(new Object[] { keyBytes, value });
	}

	public void outputDbFileContent(String vSQL, String id1, String id2,
			String fileNameField, String fileNameDefault, String fileImageField)
			throws Exception {

		Connection con = null;
		PreparedStatement vStmt = null;
		ResultSet rs = null;
		CallableStatement call = null;
		
		try {
			con = cn.connect().getConnection();

			vStmt = con.prepareStatement(vSQL);
			if (id1 != null)
				vStmt.setString(1, id1);
			if (id2 != null)
				vStmt.setString(2, id2);

			// Execute Sentence
			rs = vStmt.executeQuery();
			if (!rs.next())
				throw new Exception("File not found id = " + id1);
			String fileName = fileNameDefault;

			if (fileNameField != null)
				fileName = rs.getString(fileNameField);

			response.setContentType("text/html");

			response.setHeader("Content-disposition", "attachment; filename="+ fileName);

			BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
			if (replacePairs == null) {
				InputStream fileInputStream = rs.getBinaryStream(fileImageField);
				redirectToOut(bos, fileInputStream);
			} else {
				logger.info("usando funcion para reemplazo de campos especiales");
				byte[] fileString = rs.getBytes(fileImageField);

				int posStart = 0, bytes_send = 0;
				ReplaceInfo repInfo;
				while (posStart < fileString.length) {
					repInfo = getNextReplacement(fileString, posStart);
					if (repInfo == null) {
						bos.write(fileString, posStart, fileString.length - posStart);
						bytes_send += fileString.length - posStart;
						break;
					} else {
						bos.write(fileString, posStart, repInfo.posStart - posStart);
						bytes_send += repInfo.posStart - posStart;

						bos.write(repInfo.replaceValue, 0, repInfo.replaceValue.length);
						bytes_send += repInfo.replaceValue.length;

						posStart = repInfo.posNext;
					}
				}
				bos.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			cn.destroy(con,null,rs,call,vStmt);
		}

	}

	private ReplaceInfo getNextReplacement(byte[] fileString, int posStart) {
		// cosntruir variables de reemplazo
		if (keys == null) {
			keys = new byte[replacePairs.size()][];
			values = new String[replacePairs.size()];
			Iterator iter = replacePairs.iterator();
			for (int i = 0; iter.hasNext(); i++) {
				Object[] vObj = (Object[]) iter.next();
				keys[i] = (byte[]) vObj[0];
				values[i] = (String) vObj[1];
			}
		}

		int maxlength = fileString.length - PREFIX.length;
		while (posStart < maxlength) {
			if (fileString[posStart] == PREFIX[0]
					&& fileString[posStart + 1] == PREFIX[1]) {// rapid test
																// sin entrar a
																// func
				// Match first 2 chars -> (probable ocurrencuia) test all key
				logger.info("Replace possible match");
				for (int i = 0; i < values.length; i++) {
					if (!equals(fileString, posStart, keys[i]))
						continue;
					// match
					logger.info("Replace match found replace to :" + values[i]
							+ "|");
					ReplaceInfo repInfo = new ReplaceInfo();
					repInfo.posStart = posStart;
					repInfo.replaceValue = getAsByteArray(values[i]);// .getBytes();
					repInfo.posNext = posStart + keys[i].length;
					return repInfo;
				}
			}
			posStart++; // probar sgte caracter
		}
		return null; // no ocurence
	}

	private byte[] getAsByteArray(String str) {
		char[] strCharArray = str.toCharArray();
		byte[] strByteArray = new byte[strCharArray.length];
		for (int i = 0; i < strCharArray.length; i++) {
			strByteArray[i] = (byte) strCharArray[i];
			if (strByteArray[i] == 0)
				strByteArray[i] = 32;
		}
		return strByteArray;
	}

	private boolean equals(byte[] buffer, int pos, byte[] valueToCompare) {
		for (int i = 0; i < valueToCompare.length; i++) {
			logger.info("testing " + (char) buffer[pos + i] + " with "
					+ (char) valueToCompare[i]);
			if (buffer[pos + i] != valueToCompare[i])
				return false;
		}
		return true;
	}

	private void redirectToOut(BufferedOutputStream bos, InputStream fis)
			throws java.io.IOException {

		byte[] buffer = new byte[1024];
		int bytes_read, bytes_send = 0;
		while ((bytes_read = fis.read(buffer)) != -1) {
			bos.write(buffer, 0, bytes_read);
			bytes_send += bytes_read;
		}
		fis.close();
		bos.close();
		logger.info("bytes send " + bytes_send);
	}
	
	
	
	public void openFile(String fileName, byte[] fileImageField)
			throws Exception {

		try {
			response.setContentType("text/html");

			response.setHeader("Content-disposition", "attachment; filename="+ fileName);

			BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
			InputStream fileInputStream = new ByteArrayInputStream(fileImageField);
			redirectToOut(bos, fileInputStream);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {}

	}
	
	public void outputDbFileContentPDF(String vSQL, String id1, String id2,
			String fileNameField, String fileNameDefault, String fileImageField)
			throws Exception {

		Connection con = null;
		PreparedStatement vStmt = null;
		ResultSet rs = null;
		CallableStatement call = null;
		
		try {
			con = cn.connect().getConnection();

			vStmt = con.prepareStatement(vSQL);
			if (id1 != null)
				vStmt.setString(1, id1);
			if (id2 != null)
				vStmt.setString(2, id2);

			// Execute Sentence
			rs = vStmt.executeQuery();
			if (!rs.next())
				throw new Exception("File not found id = " + id1);
			String fileName = fileNameDefault;

//			if (fileNameField != null)
//				fileName = rs.getString(fileNameField);

//			response.setContentType("text/html"); //application/pdf
			response.setContentType("application/pdf");

			response.setHeader("Content-disposition", "attachment; filename="+ fileName);

			BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
			if (replacePairs == null) {
				InputStream fileInputStream = rs.getBinaryStream(fileImageField);
				redirectToJodPDFOut(bos, fileInputStream, fileName);
			}
//			else {
//				logger.info("usando funcion para reemplazo de campos especiales");
//				byte[] fileString = rs.getBytes(fileImageField);
//
//				int posStart = 0, bytes_send = 0;
//				ReplaceInfo repInfo;
//				while (posStart < fileString.length) {
//					repInfo = getNextReplacement(fileString, posStart);
//					if (repInfo == null) {
//						bos.write(fileString, posStart, fileString.length - posStart);
//						bytes_send += fileString.length - posStart;
//						break;
//					} else {
//						bos.write(fileString, posStart, repInfo.posStart - posStart);
//						bytes_send += repInfo.posStart - posStart;
//
//						bos.write(repInfo.replaceValue, 0, repInfo.replaceValue.length);
//						bytes_send += repInfo.replaceValue.length;
//
//						posStart = repInfo.posNext;
//					}
//				}
//				bos.close();
//			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			cn.destroy(con,null,rs,call,vStmt);
		}
	}
	
	
	private void redirectToJodPDFOut(BufferedOutputStream bos, InputStream fis,
			String fileName) throws java.io.IOException {

		ResourceBundle bundle = ResourceBundle.getBundle("com.app.sgd.resources.parameters");
		String outputDir = (String)bundle.getObject("DOWNLOAD_FILES");
//		String outputDir = Constants.DOWNLOAD_FILES;

		fileName = fileName.substring(0, fileName.length() - 4);
		String docFile = outputDir + fileName + ".doc";
		BufferedOutputStream bos1 = new BufferedOutputStream(new FileOutputStream(docFile));

		byte[] buffer = new byte[1024];
		int bytes_read, bytes_send = 0;
		while ((bytes_read = fis.read(buffer)) != -1) {
			bos1.write(buffer, 0, bytes_read);
			bytes_send += bytes_read;
		}
		fis.close();
		bos1.close();

		String pdfFile = outputDir + fileName + ".pdf";
		File inputFile = new File(docFile);
		File outputFile = new File(pdfFile);
		
		OpenOfficeConnection connection = new SocketOpenOfficeConnection("localhost", 8100);
		connection.connect();
		
		DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
		converter.convert(inputFile, outputFile);
		
		connection.disconnect();

		InputStream fileInputStream = new BufferedInputStream(new FileInputStream(pdfFile));
		buffer = new byte[1024];
		bytes_read = 0; 
		bytes_send = 0;
		while ((bytes_read = fileInputStream.read(buffer)) != -1) {
			bos.write(buffer, 0, bytes_read);
			bytes_send += bytes_read;
		}
		
		fileInputStream.close();
		bos.close();

	}
	
	
	public void outputDocumentPDFContent(String rutaPDF)
			throws Exception {
		try{
			response.setContentType("application/pdf");
			response.setHeader("Content-disposition", "attachment; filename="+ rutaPDF);

			BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
			if (replacePairs == null) {
				InputStream fis = new BufferedInputStream(new FileInputStream(rutaPDF));

				byte[] buffer = new byte[1024];
				int bytes_read, bytes_send = 0;
				while ((bytes_read = fis.read(buffer)) != -1) {
					bos.write(buffer, 0, bytes_read);
					bytes_send += bytes_read;
				}
				fis.close();
				bos.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			
		}
	}
}
